package com.dragon8869.myspringboot.controller;

import com.alibaba.fastjson.JSON;
import com.dragon8869.myspringboot.model.FileInfo;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.jodconverter.core.DocumentConverter;
import org.jodconverter.core.document.DefaultDocumentFormatRegistry;
import org.jodconverter.core.office.OfficeException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;

@Controller
@RequestMapping("file")
@Log4j2
public class FileController {

    private final static String base_uri = "/pdfjs-2.5.207-dist/web/viewer.html?file=/file/";

    @Resource
    private DocumentConverter converter;

    @GetMapping("list")
    public String list(Model model) throws IOException {
        ClassPathResource resource = new ClassPathResource("file");
        List<FileInfo> fileInfos = new ArrayList<>();
        Random random = new Random();
        for (File file : resource.getFile().listFiles()) {
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(file.getName());
            fileInfo.setContentType(Files.probeContentType(file.toPath()));
            if (fileInfo.isPdf()) {
                int i = random.nextInt(2) + 1;
                fileInfo.setUri(file.getName() + "/" + (i == 1 ? "preview" : "download"));
                fileInfo.setPreviewUri(base_uri + file.getName());
            } else {
                fileInfo.setUri(file.getName());
                fileInfo.setPreviewUri(base_uri + "covertToPdf/" + file.getName() );
            }
            fileInfos.add(fileInfo);
        }
        log.info(JSON.toJSON(fileInfos));
        model.addAttribute("fileInfos", fileInfos);
        return "files";
    }


    @GetMapping("list2")
    public String list2(Model model) throws IOException {
        ClassPathResource resource = new ClassPathResource("file");
        List<FileInfo> fileInfos = new ArrayList<>();
        Random random = new Random();
        for (File file : resource.getFile().listFiles()) {
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(file.getName());
            fileInfo.setContentType(Files.probeContentType(file.toPath()));
            fileInfo.setUri(file.getName());
            fileInfo.setPreviewUri(base_uri + (fileInfo.isPdf()?"":"covertToPdf/") + fileInfo.getUri());
            fileInfos.add(fileInfo);
        }
        log.info(JSON.toJSON(fileInfos));
        model.addAttribute("fileInfos", fileInfos);
        return "files2";
    }

    @GetMapping("{filename}")
    public void file(HttpServletResponse response, @PathVariable String filename) throws IOException {
        downloadFile(response, filename, "inline");
    }

    @GetMapping("{filename}/download")
    public void download(HttpServletResponse response, @PathVariable String filename) throws IOException {
        downloadFile(response, filename, "attachment");
    }

    @GetMapping("{filename}/preview")
    public void preview(HttpServletResponse response, @PathVariable String filename) throws IOException {
        downloadFile(response, filename, "inline");
    }

    @GetMapping("{filename}/{downloadType}")
    public void download(HttpServletResponse response, @PathVariable String filename, @PathVariable String downloadType) throws IOException {
        String contentDisposition = null;
        if ("inline".equals(downloadType) || "attachment".equals(downloadType)) {
            contentDisposition = downloadType;
        } else if ("1".equals(downloadType)) {
            contentDisposition = "inline";
        } else if ("2".equals(downloadType)) {
            contentDisposition = "attachment";
        }
        assert contentDisposition != null;
        downloadFile(response, filename, contentDisposition);
    }

    private void downloadFile(HttpServletResponse response, String filename, @NotNull String contentDisposition) throws IOException {
        ClassPathResource resource = new ClassPathResource("file/" + filename);
        response.addHeader("Content-Disposition", contentDisposition + ";filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8));
        String contentType = Files.probeContentType(resource.getFile().toPath());
        response.setContentType(contentType);
        InputStream is = resource.getInputStream();
        IOUtils.copy(is, response.getOutputStream());
        IOUtils.close(is);
    }

    @RequestMapping("covertToPdf/{filename}")
    public void covertToPdf(HttpServletResponse response, @PathVariable String filename) throws IOException, OfficeException {
        ClassPathResource resource = new ClassPathResource("file/" + filename);
        response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8));
        response.setContentType(DefaultDocumentFormatRegistry.PDF.getMediaType());
        converter.convert(resource.getFile()).to(response.getOutputStream()).as(DefaultDocumentFormatRegistry.PDF).execute();
    }


    @GetMapping("upload")
    public String upload_form() {
        return "fileUpload";
    }

    @PostMapping("upload")
    public String upload(MultipartFile[] file, MultipartHttpServletRequest request) {
        System.out.println("file = " + Arrays.deepToString(file));
        List<MultipartFile> files = request.getFiles("file");
        System.out.println("files = " + Arrays.deepToString(files.toArray()));
        ClassPathResource resource = new ClassPathResource("file");
        for (MultipartFile mf : files) {
            try {
                File f = new File(resource.getFile(), Objects.requireNonNull(mf.getOriginalFilename()));
                FileOutputStream fos = new FileOutputStream(f);
                InputStream is = mf.getInputStream();
                FileCopyUtils.copy(is, fos);
                IOUtils.close(fos);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "redirect:/file/list";
    }

}
